/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package it.polimi.games.gpicalculator;

import it.polimi.games.epkb.controller.GpiKpiJpaController;
import it.polimi.games.epkb.controller.ObservedComponentJpaController;
import it.polimi.games.epkb.entityClasses.Component;
import it.polimi.games.epkb.entityClasses.GpiKpi;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Vector;

import java.util.logging.Level;
import java.util.logging.Logger;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;

/**
 *
 * @author Filippo
 */
public class GpiCalculatorDaemon {

    /**
     * @uml.property  name="checkElement"
     * @uml.associationEnd  multiplicity="(1 1)"
     */
    private String mFilePath;
    private String octavePath;
    boolean exitCondition = true;
    ArrayList<GpiCalculatorThread> threads = new ArrayList<GpiCalculatorThread>();
    private boolean running = false;
    EntityManagerFactory emfEpkb;
    EntityManagerFactory emfFcim;
    GpiKpiJpaController gpiKpiC;
    ObservedComponentJpaController ocC;

    public GpiCalculatorDaemon(String mFilePath, String octavePath, long daemonDuration, long gpiKpiRefreshPeriod) {

        this.mFilePath = mFilePath;
        this.octavePath = octavePath;

    }

    public void run() {

        emfEpkb = Persistence.createEntityManagerFactory("EPKB-PU");
        emfFcim = Persistence.createEntityManagerFactory("FCIM-PU");
        gpiKpiC = new GpiKpiJpaController(emfEpkb);
        ocC = new ObservedComponentJpaController(emfEpkb);

        Collection<GpiKpi> cGpiKpi = gpiKpiC.findGpiKpiEntities();

        for (GpiKpi indicator : cGpiKpi) {


                //EntityManagerFactory emfEpkbThread = Persistence.createEntityManagerFactory("EPKB-PU");
                //EntityManagerFactory emfFcimThread = Persistence.createEntityManagerFactory("FCIM-PU");
            
                GpiCalculator gpiCalculator = new GpiCalculator(mFilePath, octavePath, emfEpkb, emfFcim);

                GpiCalculatorThread thread = new GpiCalculatorThread(indicator, gpiCalculator, emfEpkb);

                Logger.getLogger(GpiCalculatorDaemon.class.getName()).log(Level.INFO, "Strarting thread for gpikpi " + indicator.getName());

                threads.add(thread);
                thread.start();                

        }


        this.running = true;

    }

    public void done() {

        for (GpiCalculatorThread thread : threads) {

            if (thread != null && thread.isAlive()) {
                thread.done();
            }
        }

        if (this.emfEpkb != null && this.emfEpkb.isOpen()) {

            this.emfEpkb.close();
        }


        this.running = false;

    }

    public boolean isRunning() {

        return this.running;
    }

    /*public void tun() {
    
    Timestamp nextGpiKpiRefresh = new Timestamp(System.currentTimeMillis() - 1000);
    
    GpiCalculator gc = new GpiCalculator(mFilePath, octavePath);
    
    EntityManagerFactory emfEpkb = Persistence.createEntityManagerFactory("EPKB-PU");
    GpiKpiJpaController gpiKpiC = new GpiKpiJpaController(emfEpkb);
    ObservedComponentJpaController ocC = new ObservedComponentJpaController(emfEpkb);
    
    Collection<GpiKpi> cGpiKpi = gpiKpiC.findGpiKpiEntities();
    Iterator<GpiKpi> iGpiKpi = cGpiKpi.iterator();
    
    Vector<checkElement> lle = new Vector<checkElement>();
    
    /// do-while
    Timestamp endTime = new Timestamp(System.currentTimeMillis() + daemonDuration * 1000);
    Timestamp nowTime = new Timestamp(System.currentTimeMillis());
    
    
    
    
    do {
    //     if (nextGpiKpiRefresh.before(nowTime)) {
    // update Gpi/Kpi list
    //System.out.println(nowTime+"... Update Gpi/Kpi List");
    cGpiKpi = gpiKpiC.findGpiKpiEntities();
    iGpiKpi = cGpiKpi.iterator();
    lle = new Vector<checkElement>();
    
    while (iGpiKpi.hasNext()) {
    GpiKpi gk = iGpiKpi.next();
    
    Query q1 = ocC.getEntityManager().createQuery("SELECT DISTINCT s.idComponent FROM GpiKpiInstance s WHERE s.idGPIKPI=?1");
    q1.setParameter(1, gpiKpiC.findGpiKpi(gk.getId()));
    
    Collection<Component> c = q1.getResultList();
    Iterator<Component> i = c.iterator();
    long updateFrequency;
    while (i.hasNext()) {
    Component v = i.next();
    if ((gk.getUpdateFrequency() == null) || (gk.getUpdateFrequency().longValue() <= 0)) {
    // if the update frequency is null or is a negative value, a default value of 10 seconds is set
    updateFrequency = 10;
    } else {
    updateFrequency = gk.getUpdateFrequency().longValue();
    }
    checkElement f = new checkElement(gk.getId(), v.getId(), updateFrequency, new Timestamp(System.currentTimeMillis() + updateFrequency * 1000));
    
    Logger.getLogger(GpiCalculator.class.getName()).log(Level.INFO, "Calculating gpikpi " + gk.getName() + " on component " + v.getId());
    
    gc.calculateGpi(gk.getId(), v.getId());
    
    Logger.getLogger(GpiCalculator.class.getName()).log(Level.INFO, "Calculated gpikpi " + gk.getName() + " on component " + v.getId());
    
    lle.add(f);
    }
    }
    // update of the next GpiKpi refresh instant
    nextGpiKpiRefresh = new Timestamp(System.currentTimeMillis() + gpiKpiRefreshPeriod * 1000);
    // }
    
    for (checkElement v : lle) {
    nowTime = new Timestamp(System.currentTimeMillis());
    if (v.getNextComputationTimestamp().before(nowTime)) {
    //eseguo
    gc.calculateGpi(v.getGpiKpiId(), v.getComponentId());
    
    v.setNextComputationTimestamp(new Timestamp(System.currentTimeMillis() + v.getFrequency() * 1000));
    //System.out.print(nowTime + " ... ");
    //System.out.println(v);
    }
    }
    
    if (daemonDuration == 0) {
    exitCondition = true;
    } else {
    exitCondition = nowTime.before(endTime);
    }
    
    
    } while (exitCondition);
    
    // close connections
    gc.closeGpiCalculator();
    
    
    
    }
    
    public void done() {
    this.exitCondition = false;
    }
    }
    
    class checkElement {
    
    private String gpiKpiId;
    private String componentId;
    private long frequency;
    private Timestamp nextComputationTimestamp;
    
    public checkElement(String gpiKpiId, String componentId, long frequency, Timestamp nextComputationTimestamp) {
    this.gpiKpiId = gpiKpiId;
    this.componentId = componentId;
    this.frequency = frequency;
    this.nextComputationTimestamp = nextComputationTimestamp;
    }
    
    public String getGpiKpiId() {
    return gpiKpiId;
    }
    
    public String getComponentId() {
    return componentId;
    }
    
    public long getFrequency() {
    return frequency;
    }
    
    public Timestamp getNextComputationTimestamp() {
    return nextComputationTimestamp;
    }
    
    public void setNextComputationTimestamp(Timestamp nextComputationTimestamp) {
    this.nextComputationTimestamp = nextComputationTimestamp;
    }
    
    @Override
    public String toString() {
    return gpiKpiId + " - " + componentId + " - " + frequency + " - " + nextComputationTimestamp;
    }*/
}